//// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
//package com.linqingying.gitcode.pullrequest.ui.diff
//
//import com.intellij.collaboration.async.*
//import com.intellij.collaboration.ui.codereview.diff.DiffLineLocation
//import com.intellij.collaboration.ui.codereview.diff.DiscussionsViewOption
//import com.intellij.collaboration.util.RefComparisonChange
//import com.intellij.collaboration.util.filePath
//import com.intellij.collaboration.util.getOrNull
//import com.intellij.diff.util.Range
//import com.intellij.openapi.diff.impl.patch.PatchHunkUtil
//import com.intellij.openapi.diff.impl.patch.TextFilePatch
//import com.intellij.platform.util.coroutines.childScope
//import com.intellij.vcsUtil.VcsFileUtil
//import git4idea.changes.GitTextFilePatchWithHistory
//import kotlinx.coroutines.CoroutineScope
//import kotlinx.coroutines.flow.StateFlow
//import kotlinx.coroutines.flow.combine
//import kotlinx.coroutines.flow.map
//import kotlinx.coroutines.flow.mapNotNull
//import com.linqingying.gitcode.api.data.pullrequest.GCPullRequestReviewThread
//import com.linqingying.gitcode.api.data.pullrequest.isVisible
//import com.linqingying.gitcode.api.data.pullrequest.mapToLocation
//import com.linqingying.gitcode.pullrequest.data.GCPRDataContext
//import com.linqingying.gitcode.pullrequest.data.provider.GCPRDataProvider
//import com.linqingying.gitcode.pullrequest.data.provider.createThreadsRequestsFlow
//import com.linqingying.gitcode.pullrequest.ui.comment.GCPRReviewCommentLocation
//import com.linqingying.gitcode.pullrequest.ui.comment.GCPRReviewCommentPosition
//import com.linqingying.gitcode.pullrequest.ui.comment.GCPRThreadsViewModels
//import com.linqingying.gitcode.pullrequest.ui.comment.lineLocation
//import com.linqingying.gitcode.pullrequest.ui.editor.GCPRReviewNewCommentEditorViewModel
//
//interface GCPRDiffChangeViewModel {
//  val commentableRanges: List<Range>
//  val canComment: Boolean
//
//  val threads: StateFlow<Collection<GCPRReviewThreadDiffViewModel>>
//  val newComments: StateFlow<Collection<GCPRNewCommentDiffViewModel>>
//
//  val locationsWithDiscussions: StateFlow<Set<DiffLineLocation>>
//
//  fun requestNewComment(location: GCPRReviewCommentLocation, focus: Boolean)
//  fun cancelNewComment(location: GCPRReviewCommentLocation)
//
//  fun markViewed()
//}
//
//internal class GCPRDiffChangeViewModelImpl(
//  parentCs: CoroutineScope,
//  private val dataContext: GCPRDataContext,
//  private val dataProvider: GCPRDataProvider,
//  private val change: RefComparisonChange,
//  private val diffData: GitTextFilePatchWithHistory,
//  private val threadsVms: GCPRThreadsViewModels,
//  private val discussionsViewOption: StateFlow<DiscussionsViewOption>
//) : GCPRDiffChangeViewModel {
//  private val cs = parentCs.childScope(classAsCoroutineName())
//
//  override val commentableRanges: List<Range> = diffData.patch.ranges
//  override val canComment: Boolean = threadsVms.canComment
//
//  private val mappedThreads: StateFlow<Map<String, MappedGCPRReviewThreadDiffViewModel.MappingData>> =
//    dataProvider.reviewData.createThreadsRequestsFlow()
//      .computationState()
//      .transformConsecutiveSuccesses(false) {
//        combine(this, discussionsViewOption) { threads, viewOption ->
//          threads.associateBy(GCPullRequestReviewThread::id) { threadData ->
//            val isVisible = threadData.isVisible(viewOption)
//            val location = threadData.mapToLocation(diffData)
//            MappedGCPRReviewThreadDiffViewModel.MappingData(isVisible, location)
//          }
//        }
//      }.map { it.getOrNull().orEmpty() }.stateInNow(cs, emptyMap())
//
//  override val threads: StateFlow<Collection<GCPRReviewThreadDiffViewModel>> =
//    threadsVms.compactThreads.mapModelsToViewModels { sharedVm ->
//      MappedGCPRReviewThreadDiffViewModel(this, sharedVm, mappedThreads.mapNotNull { it[sharedVm.id] })
//    }.stateInNow(cs, emptyList())
//
//  override val locationsWithDiscussions: StateFlow<Set<DiffLineLocation>> =
//    mappedThreads.map {
//      it.values.mapNotNullTo(mutableSetOf()) { (isVisible, location) -> location?.takeIf { isVisible } }
//    }.stateInNow(cs, emptySet())
//
//  private val newCommentsContainer =
//    MappingScopedItemsContainer.byIdentity<GCPRReviewNewCommentEditorViewModel, GCPRNewCommentDiffViewModelImpl>(cs) {
//      GCPRNewCommentDiffViewModelImpl(it.position.location.lineLocation, it)
//    }
//  override val newComments: StateFlow<Collection<GCPRNewCommentDiffViewModel>> =
//    newCommentsContainer.mappingState.mapState { it.values }
//
//  init {
//    cs.launchNow {
//      threadsVms.newComments.collect {
//        val commentForChange = it.values.filter { it.position.change == change }
//        newCommentsContainer.update(commentForChange)
//      }
//    }
//  }
//
//  override fun requestNewComment(location: GCPRReviewCommentLocation, focus: Boolean) {
//    val position = GCPRReviewCommentPosition(change, location)
//    val sharedVm = threadsVms.requestNewComment(position)
//    if (focus) {
//      cs.launchNow {
//        newCommentsContainer.addIfAbsent(sharedVm).requestFocus()
//      }
//    }
//  }
//
//  override fun cancelNewComment(location: GCPRReviewCommentLocation) {
//    val position = GCPRReviewCommentPosition(change, location)
//    threadsVms.cancelNewComment(position)
//  }
//
//  override fun markViewed() {
//    if (!diffData.isCumulative) return
//    val repository = dataContext.repositoryDataService.repositoryMapping.gitRepository
//    val repositoryRelativePath = VcsFileUtil.relativePath(repository.root, change.filePath)
//
//    dataProvider.viewedStateData.updateViewedState(repositoryRelativePath, true)
//  }
//}
//
//private val TextFilePatch.ranges: List<Range>
//  get() = hunks.map(PatchHunkUtil::getRange)
